<?php

class HelpTask extends \Phalcon\CLI\Task
{
    const SPACE_LENGTH   = 2;
    const MAX_STR_LENGTH = 80;

    public function mainAction()
    {
        $task = $this->dispatcher->getParam('task');

        if (! $task)
            $this->displayCommands();
        elseif ($task == 'help')
            $this->displayIntro($task);
        else
            $this->displayHelp($task);
    }

    public function displayIntro($task, $data = array())
    {
        if ($task == 'help') {
            cli_output('使用方法: help [task-name]');
        } else {
            if (! empty($data['description'])) {
                cli_output($data['description'] . PHP_EOL);
            }
            cli_output('使用方法:', 'notice');
            if (empty($data['usage'])) {
                cli_output(lcfirst($task) . ($data['hasOptions']?' [参数列表]' : '') . PHP_EOL);
            } else {
                foreach ($data['usage'] as $usage) {
                    cli_output($usage);
                }
                cli_output();
            }
        }
    }

    public function displayCommands()
    {
        $namespace = $this->dispatcher->getDefaultNamespace();
        cli_output('可用命令:', 'notice');
        foreach (new \DirectoryIterator(APP_PATH . '/tasks') as $fileInfo) {
            $filename = $fileInfo->getFilename();
            $task     = substr($filename, 0, -8);
            if (strtolower(substr($filename, -8)) == 'task.php' && class_exists("$namespace\\{$task}Task")) {
                echo lcfirst($task) . PHP_EOL;
            }
        }
    }

    public function displayOptions($options)
    {
        cli_output('参数列表:', 'notice');

        $maxShortLength = 0;
        $maxLongLength  = 0;
        $hasRequired    = false;

        foreach ($options as $option) {
            if (($shortLength = strlen($option['short'])) > $maxShortLength) $maxShortLength = $shortLength;
            if (($longLength  = strlen($option['long']))  > $maxLongLength)  $maxLongLength  = $longLength;
            $hasRequired = $hasRequired || $option['required'];
        }

        foreach ($options as $option) {
            $line = $option['short']
                ? '-' .$option['short'].str_repeat(' ', $maxShortLength + self::SPACE_LENGTH - strlen($option['short']))
                : str_repeat(' ', $maxShortLength + 1 + self::SPACE_LENGTH);
            $line .= $option['long']
                ? '--'.$option['long'].str_repeat(' ', $maxLongLength + self::SPACE_LENGTH - strlen($option['long']))
                : str_repeat(' ', $maxLongLength + 2 + self::SPACE_LENGTH);

            $descrLength   = strlen($option['description']);
            $lineLength    = strlen($line);
            $leadingSpaces = str_repeat(' ', $maxShortLength + $maxLongLength + 3 + self::SPACE_LENGTH * 2);

            if ($hasRequired) {
                $line .= ($option['required'] ? '!' : ' ').str_repeat(' ', self::SPACE_LENGTH);
                $leadingSpaces .= str_repeat(' ', 1 + self::SPACE_LENGTH);
            }

            $line .= $lineLength < self::MAX_STR_LENGTH && self::MAX_STR_LENGTH < $descrLength + $lineLength
                ? rtrim(chunk_split($option['description'], self::MAX_STR_LENGTH - $lineLength, PHP_EOL . $leadingSpaces))
                : $option['description'];

            cli_output($line);
        }

        if ($hasRequired) {
            cli_output(PHP_EOL . '"!" 为必选项', 'import');
        }
    }

    public function displayHelp($task)
    {
        $namespace = $this->dispatcher->getDefaultNamespace();

        if (! class_exists("$namespace\\{$task}Task")) {
            cli_error("未知任务 '$task'");
        }

        $reflection = new \ReflectionClass("$namespace\\{$task}Task");

        $instance = $reflection->newInstance();
        $instance->registerOptions();
        $options = $instance->getOptionDetails();

        $description = $this->parseComment($reflection->getDocComment());
        $description['hasOptions'] = ! empty($options);
        $this->displayIntro($task, $description);

        if (! empty($options)) {
            $this->displayOptions($options);
        }
    }

    public function parseComment($comment)
    {
        $beforeAT = true;
        $result   = array(
            'usage'       => array(),
            'description' => array(),
        );

        foreach (preg_split("/\r\n|\n/", $comment) as $line) {
            if (! $line = ltrim($line, "/* \t")) {
                continue;
            }

            if ($line[0] == '@') {
                $beforeAT = false;
            }

            if ($beforeAT) {
                $result['description'][] = $line;
            }

            if (substr($line, 0, 10) == '@cli-usage') {
                $result['usage'][] = trim(substr($line, 10));
            }
        }

        $result['description'] = join(PHP_EOL, $result['description']);

        return $result;
    }
}
